﻿using AutoMapper;
using Max.PH4.Shoppgin.Admin.Domain;
using Max.PH4.Shoppgin.Admin.Domain.Shared;
using Max.PH4.Shoppgin.Admin.DTO;
using Max.PH4.Shoppgin.Admin.IRespository;
using Max.PH4.Shoppgin.Admin.IService;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Max.PH4.Shoppgin.Admin.Service
{
    public class OrderMasterService : IOrderMasterService
    {
        IOrderMasterRespository _orderMasterRespository;
        IOrderDetailRespository _orderDetailRespository;
        ILogisticMasterRespository _logisticMasterRespository;
        ILogisticDetailRespository _logisticDetailRespository;
        ISKURespository _skuRespository;
        IUnitOfWork _unitOfWork;
        IMapper _map;

        public OrderMasterService(IOrderMasterRespository orderMasterRespository, IUnitOfWork unitOfWork, IOrderDetailRespository orderDetailRespository, IMapper map, ILogisticMasterRespository logisticMasterRespository, ILogisticDetailRespository logisticDetailRespository, ISKURespository skuRespository)
        {
            _orderMasterRespository = orderMasterRespository;
            _unitOfWork = unitOfWork;
            _orderDetailRespository = orderDetailRespository;
            _map = map;
            _logisticMasterRespository = logisticMasterRespository;
            _logisticDetailRespository = logisticDetailRespository;
            _skuRespository = skuRespository;
        }


        /*
         * 订单的操作
         * 1、添加订单主表信息
         * 2、添加这个订单对应的商品信息（会有多个商品）
         * 3、修改这个订单中的商品的可用库存-------就体现出来了锁的作用了
         * 
         * **/

        //创建订单
        public void CreateOrder()
        {
            /*
             * 订单主表和订单商品信息是一对多的关系，所以是一个订单主表和多个订单商品
             * **/
            var order = new OrderMasterEntity();//订单主表信息
            var details = new List<OrderDetailEntity>();//多个订单商品信息

            using (var tran = _unitOfWork.GetMyDbContext().Database.BeginTransaction())
            {
                try
                {
                    _orderMasterRespository.Insert(order); //单个添加
                    _orderDetailRespository.Insert(details); //批量添加

                    //修改库存（有锁则报异常）
                    details.ForEach(x =>
                    {
                        bool a = false;
                        do
                        {
                            //根据添加到订单中的商品Id,从商品sku表中，把这个商品找出来
                            //去修改它的可用库存和锁定库存
                            var m = _skuRespository.Query().Where(s => s.Id == x.SKUId).FirstOrDefault();

                            if (m != null)
                            {
                                try
                                {
                                    //sku表中，商品的可用库存减少，锁定库存增加
                                    m.ValidStock -= Convert.ToInt32(x.SKUNumber);
                                    m.LockStock += Convert.ToInt32(x.SKUNumber);
                                    _skuRespository.Update(m);
                                    _unitOfWork.SaveChanges();
                                    a = true;
                                }
                                catch (DbUpdateConcurrencyException)
                                {
                                    a = false;
                                }
                            }
                            else
                            {
                                a = true;
                            }
                        }while (a) ;

                    });


                    _unitOfWork.SaveChanges();

                    tran.Commit();
                }
                catch (Exception)
                {
                    tran.Rollback();
                    throw;
                }
            }
        }




        public async Task<int> DeleteAsync(OrderMasterEntity entity)
        {
            _orderMasterRespository.Delete(entity);
            int result = await _unitOfWork.SaveChangesAsync();
            return result;
        }

        public async Task<int> DeleteAsync(object id)
        {
            _orderMasterRespository.Delete(id);
            int result = await _unitOfWork.SaveChangesAsync();
            return result;
        }

        /// <summary>
        /// 添加订单
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public int Insert(OrderInputDto dto)
        {
            int result = 0;
            using (var tran = _unitOfWork.GetMyDbContext().Database.BeginTransaction()) //开启事务
            {
                try
                {
                    //添加订单数据：即添加订单主表信息和订单明细表信息。
                    //其中订单主表信息只有一条，订单明细表即订单对应的商品会有多条
                    OrderMasterEntity master = new OrderMasterEntity();
                    List<OrderDetailEntity> details = new List<OrderDetailEntity>();

                    //用Automapper自动映射组件，将前台传过来的数据分别映射到订单和订单明细实体上
                    master = _map.Map<OrderInputDto, OrderMasterEntity>(dto);
                    details = _map.Map<List<OrderDetailInputDto>, List<OrderDetailEntity>>(dto.Details);

                    //执行订单添加
                    _orderMasterRespository.Insert(master);

                    //订单明细表和订单表的关联是通过订单号来的，所以需要往订单明细数据中添加主表的订单号
                    details.ForEach(x =>
                    {
                        x.OrderNo = master.OrderNo;
                    });
                    //执行订单明细表添加
                    _orderDetailRespository.Insert(details);

                    //提交到数据，用的是工作单元统一提交
                    result = _unitOfWork.SaveChanges();

                    tran.Commit(); //提交事务
                }
                catch (Exception)
                {
                    result = -1;
                    tran.Rollback(); //回滚事务
                    throw;
                }
            }

            return result;
        }

        public async Task<IQueryable<OrderMasterEntity>> QueryAsync()
        {
            IQueryable<OrderMasterEntity> list = null;
            await Task.Run(() =>
            {
                list = _orderMasterRespository.Query();
            });
            return list;
        }






        public async Task<IQueryable<OrderMasterEntity>> QueryAsync(string orderNo)
        {
            IQueryable<OrderMasterEntity> list = null;
            await Task.Run(() =>
            {
                list = _orderMasterRespository.Query().Where(x => x.OrderNo.Contains(orderNo));
            });
            return list;
        }


        public dynamic Query()
        {
            var order = _orderMasterRespository.Query();

            var q = from a in order
                    select new
                    {
                        id = a.Id,
                        orderNo = a.OrderNo,
                        member = a.MemberId.ToString(),
                        amount = a.OrderAmount,
                        date = a.OrderTime.ToString("yyyy-MM-dd hh:mm:ss"),
                        state = a.OrderState,
                        products = _orderDetailRespository.Query().Where(x => x.OrderNo.Equals(a.OrderNo)).ToList(),
                        isChecked = false
                    };
            return q;
        }


        public IQueryable<OrderMasterEntity> Query(string orderNo, string state, int pageIndex, int pageSize, out int total)
        {
            IQueryable<OrderMasterEntity> list = null;

            list = _orderMasterRespository.Query().Where(x => x.OrderNo.Contains(orderNo));

            if (!state.Equals("-1"))
                list = list.Where(x => state.Equals(((int)x.OrderState).ToString()));

            total = list.Count();

            list = list.Skip((pageIndex - 1) * pageSize).Take(pageSize);
            return list;
        }

        public async Task<int> UpdateAsync(OrderMasterEntity entity)
        {
            _orderMasterRespository.Update(entity);
            int result = await _unitOfWork.SaveChangesAsync();
            return result;

        }

        public async Task<int> UpdateAsync(List<OrderMasterEntity> entities)
        {
            _orderMasterRespository.Update(entities);
            int result = await _unitOfWork.SaveChangesAsync();
            return result;
        }


        public dynamic GetOrderDetail(string orderNo)
        {
            //1、订单信息
            //2、订单的商品信息
            //3、订单的物流信息

            var master = _orderMasterRespository.Query()
                            .Where(x => x.OrderNo.Equals(orderNo))
                            .Select(x => new
                            {
                                orderNo = x.OrderNo,
                                x.OrderAmount,
                                orderTime = x.OrderTime.ToString("yyyy-MM-dd hh:mm:ss"),
                                x.RecivedAddress,
                                x.RecivedName,
                                x.RecivedPhone,
                                x.Remark
                            })
                            .FirstOrDefault();
            var details = _orderDetailRespository.Query().Where(x => x.OrderNo.Equals(orderNo));

            var lm = _logisticMasterRespository.Query().Where(x => x.OrderNo.Equals(orderNo)).FirstOrDefault();


            IQueryable<dynamic> logisticDetails = null;
            //该订单没有物流的情况下，则不需要查询物流明细（即物流详细记录）
            if (lm != null)
            {
                logisticDetails = _logisticDetailRespository.Query().Where(x => x.DeliveryNo.Equals(lm.DeliveryNo))
                    .OrderBy(x => x.DeliveryTime)
                    .Select(x => new
                    {
                        x.Context,
                        DeliveryTime = x.DeliveryTime.ToString("yyyy-MM-dd hh:mm:ss")
                    });
            }

            return new { master, details, logisticDetails };
        }


        #region 枚举反射

        //System.Type
        //System.Reflection


        public List<dynamic> GetPayEnumBind()
        {
            List<dynamic> list = new List<dynamic>(); //这个集合是用来存放枚举的数据
            //获取这个枚举的类型
            var t = typeof(PayTypeEnum);
            //获取这个枚举中具体的所有字段
            var fs = t.GetFields();
            //因为上面获取的是所有的字段，所以要循环获取具体某个字段的Display
            fs.ToList().ForEach(x =>
            {
                if (!x.Name.Equals("value__"))
                {
                    //获取具体某个字段的display特性
                    var objs = x.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.DisplayAttribute), true);
                    int v = (int)Enum.Parse(t, x.Name); //拿到这个字段对应的值
                    string n = "";
                    //获取到特性之后，去判断是否存
                    if (objs != null && objs.Length > 0)
                    {
                        //存在，则可以获取这个display特性的name属性(只取第0个的特性)
                        n = ((System.ComponentModel.DataAnnotations.DisplayAttribute)objs[0]).Name;
                    }
                    else
                    {
                        //不存在display特性，那么就获取这个字段本身的名称
                        n = x.Name;
                    }
                    list.Add(new { id = v, name = n });
                }
            });

            return list;
        }


        #endregion
    }


}
